package javafoundations;

import java.util.Iterator;


public class LinkedBinaryTree<T> implements BinaryTree<T> {
   public BTNode<T> root;
   public BTNode left;
   public BTNode right;

   public LinkedBinaryTree()
   {
      root = null;
   }
   public LinkedBinaryTree (T element)
   {
      root = new BTNode<T>(element);
   }
   public LinkedBinaryTree (T element, LinkedBinaryTree<T> left, LinkedBinaryTree<T> right)
   {
      root = new BTNode<T>(element);
      root.setLeft(left.root);
      root.setRight(right.root);
   }
   public T getRootElement() throws Exception {
      if (root == null)
         throw new Exception ("get root operation "
                 + "failed. the tree is empty.");
      return root.getElement();
   }
   public LinkedBinaryTree<T> getLeft() throws Exception {
      if (root == null)
         throw new Exception ("get left operation "
                 + "failed. the tree is empty.");

      LinkedBinaryTree<T> result = new LinkedBinaryTree<T>();
      result.root = root.getLeft();

      return result;
   }
   public T find (T target) throws Exception {
      BTNode<T> node = null;

      if (root != null)
         node = root.find(target);

      if (node == null)
         throw new Exception("find operation failed. "
                 + "no such element in tree.");

      return node.getElement();
   }
   public int size()
   {
      int result = 0;

      if (root != null)
         result = root.count();

      return result;
   }
   public Iterator<T> inorder()
   {
      ArrayIterator<T> iter = new ArrayIterator<T>();

      if (root != null)
         root.inorder (iter);

      return  iter;
   }
   public Iterator<T> levelorder() throws EmptyCollectionException {
      LinkedQueue<BTNode<T>> queue = new LinkedQueue<BTNode<T>>();
      ArrayIterator<T> iter = new  ArrayIterator<T>();

      if (root != null)
      {
         queue.enqueue(root);
         while (!queue.isEmpty())
         {
            BTNode<T> current = queue.dequeue();

            iter.add (current.getElement());

            if (current.getLeft() != null)
               queue.enqueue(current.getLeft());
            if (current.getRight() != null)
               queue.enqueue(current.getRight());
         }
      }

      return iter;
   }
   public Iterator<T> ArrayIterator()
   {
      return inorder();
   }
   public LinkedBinaryTree<T> getRight() throws Exception {
      if (root == null)
         throw new Exception ("get Right operation "
                 + "failed. the tree is empty.");
      LinkedBinaryTree<T> result = new LinkedBinaryTree<T>();
      result.root = root.getRight();

      return result;
   }
   public boolean contains (T target) throws Exception {
      BTNode<T> node = null;
      boolean result = true;
      if (root != null)
         node = root.find(target);
      if(node == null)
         result = false;
      return result;
   }
   public boolean isEmpty() {
      return (root.count()==0);
   }
   public String toString() {
      ArrayIterator<T> list = (ArrayIterator<T>) preorder();
      String result = "<top of Tree>\n";
      for(T i : list){
         result += i + "\t";
      }
      return result + "<bottom of Tree>";
   }
   public  Iterator<T> preorder() {
      ArrayIterator<T> list = new  ArrayIterator<>();

      if(root!=null)
         root.preorder(list);
      return list;
   }

   public  Iterator<T> postorder() {
      ArrayIterator<T> list = new  ArrayIterator<>();

      if(root!=null)
         root.postorder(list);
      return list;
   }



   @Override
   public Iterator<T> iterator() {
      return null;
   }
}
